home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / checkbox / scripts / suspend_test < prev   
Encoding:
Text File  |  2009-04-27  |  14.2 KB  |  613 lines

  1. #!/bin/bash
  2. #
  3. # Script to automate suspend / resume
  4. #
  5. # Copyright (C) 2008-2009 Canonical Ltd.
  6. #
  7. # Authors:
  8. #  Michael Frey <michael.frey@canonical.com>
  9. #  Andy Whitcroft <apw@canonical.com>
  10. #
  11. # This program is free software: you can redistribute it and/or modify
  12. # it under the terms of the GNU General Public License version 2,
  13. # as published by the Free Software Foundation.
  14. #
  15. # This program is distributed in the hope that it will be useful,
  16. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. # GNU General Public License for more details.
  19. #
  20. # You should have received a copy of the GNU General Public License
  21. # along with this program.  If not, see <http://www.gnu.org/licenses/>.
  22.  
  23. #
  24. # Script to automate suspend / resume
  25. #
  26. # We set a RTC alarm that wakes the system back up and then sleep
  27. # for  seconds before we go back to sleep.
  28. #
  29. # Changelog:
  30. #
  31. # V8:
  32. #  - add a new suspend battery drain test
  33. #  - track batteries disabling tests which require them automatically
  34. #  - disable dbus tests when we have no primary user
  35. #  - include the new power drain test in --full
  36. #  - handle AC transitions better
  37. #  - use minutes in messages where appropriate
  38. #  - report AC transition failures
  39. #  - only mention AC when we have batteries
  40. #  - report results at the bottom for easy posting
  41. #
  42. # V7:
  43. #  - add a --dry-run mode to simplify developement
  44. #  - add a automation mode for checkbox integration
  45. #  - add a new pm-suspend test
  46. #  - record and restore timer_delay around the variable time test.
  47. #
  48. # V6:
  49. #  - move an --enable/--disable interface for tests
  50. #  - add --set to allow setting of approved parameters
  51. #  - fix up prompting for interactive and non-interactive tests
  52. #  - supply a sensible default for testing on servers (apw, kirkland)
  53. #
  54. # V5:
  55. #  - send dbus messages as the original user
  56. #  - stop clearing the dmesg as we go
  57. #  - stop using trace generally as this affects the wakeups
  58. #  - do a single dbus test then move to pm-suspend to avoid screensaver
  59. #  - timeout waiting for a suspend to complete catching failure to go down
  60. #
  61. # V4:
  62. #  - update the help output
  63. #  - add --comprehensive to do AC related tests
  64. #  - add --extensive to do a range of time related tests
  65. #  - add --full to enable all harder tests
  66. #  - add fallback to pm-suspend for Kbuntu
  67. #  - collect dmesg output
  68. #  - remove hwclock update
  69. #
  70. # V3:
  71. #  - fix typo in fallback acpi interface
  72. #  - when recording the RTC clock do not go direct
  73. #  - pmi is now deprecated suspend using dbus
  74. #
  75. # V2:
  76. #  - support newer rtc sysfs wakealarm interface
  77. #  - move to using pmi action suspend
  78. #  - allow the user to specify the number of iterations
  79. #  - ensure we are running as root
  80. #  - report the iterations to the user
  81. #  - clean up the output and put it in a standard logfile
  82. #  - add a descriptive warning and allow user cancel
  83. #  - add tracing enable/disable
  84. #  - fix logfile location
  85. #  - add a failure cleanup mode
  86. #  - make time sleep time and delay time configurable
  87. #  - ensure the log directory exists
  88. #  - clock will be fixed automatically on network connect
  89. #  - default sleep before wakeup to 20s
  90. #  - do not use dates after we have corrupted the clock
  91. #  - sort out the copyright information
  92. #  - we do not have any failure cleanup currently
  93. #
  94. # V1:
  95. #  - add the suspend test scripts
  96. #
  97. P="test-suspend"
  98.  
  99. LOGDIR='/var/lib/pm-utils'
  100. LOGFILE="$LOGDIR/stress.log"
  101.  
  102. setup_wakeup_timer ()
  103. {
  104.     timeout="$1"
  105.  
  106.     #
  107.     # Request wakeup from the RTC or ACPI alarm timers.  Set the timeout
  108.     # at 'now' + $timeout seconds.
  109.     #
  110.     ctl='/sys/class/rtc/rtc0/wakealarm'
  111.     if [ -f "$ctl" ]; then
  112.         time=`date '+%s' -d "+ $timeout seconds"`
  113.         # Cancel any outstanding timers.
  114.         echo "0" >"$ctl"
  115.         # rtcN/wakealarm uses absolute time in seconds
  116.         echo "$time" >"$ctl"
  117.         return 0
  118.     fi
  119.     ctl='/proc/acpi/alarm'
  120.     if [ -f "$ctl" ]; then
  121.         echo `date '+%F %H:%M:%S' -d '+ '$timeout' seconds'` >"$ctl"
  122.         return 0
  123.     fi
  124.  
  125.     echo "no method to awaken machine automatically" 1>&2
  126.     exit 1
  127. }
  128.  
  129. suspend_system ()
  130. {
  131.     if [ "$dry" -eq 1 ]; then
  132.         echo "DRY-RUN: suspend machine for $timer_sleep"
  133.         sleep 1
  134.         return
  135.     fi
  136.  
  137.     setup_wakeup_timer "$timer_sleep"
  138.  
  139.     dmesg >"$LOGFILE.dmesg.A"
  140.  
  141.     # Send a dbus message to initiate Suspend.
  142.     if [ "$suspend_dbus" -eq 1 ]; then
  143.         sudo -u $SUDO_USER dbus-send --session --type=method_call \
  144.             --dest=org.freedesktop.PowerManagement \
  145.             /org/freedesktop/PowerManagement \
  146.             org.freedesktop.PowerManagement.Suspend \
  147.             >> "$LOGFILE" || {
  148.                 ECHO "FAILED: dbus suspend failed"
  149.                 return
  150.             }
  151.     else
  152.         pm-suspend >> "$LOGFILE"
  153.     fi
  154.  
  155.     # Wait on the machine coming back up -- pulling the dmesg over.
  156.     echo "v---" >>"$LOGFILE"
  157.     retry=30
  158.     while [ "$retry" -gt 0 ]; do
  159.         let "retry=$retry-1"
  160.  
  161.         # Accumulate the dmesg delta.
  162.         dmesg >"$LOGFILE.dmesg.B"
  163.         diff "$LOGFILE.dmesg.A" "$LOGFILE.dmesg.B" | \
  164.             grep '^>' >"$LOGFILE.dmesg"
  165.         mv "$LOGFILE.dmesg.B" "$LOGFILE.dmesg.A"
  166.  
  167.         echo "Waiting for suspend to complete $retry to go ..." \
  168.                             >> "$LOGFILE"
  169.         cat "$LOGFILE.dmesg" >> "$LOGFILE"
  170.  
  171.         if [ "`grep -c 'Back to C!' $LOGFILE.dmesg`" -ne 0 ]; then
  172.             break;
  173.         fi
  174.         sleep 1
  175.     done
  176.     echo "^---" >>"$LOGFILE"
  177.     rm -f "$LOGFILE.dmesg"*
  178.     if [ "$retry" -eq 0 ]; then
  179.         ECHO "SUSPEND FAILED, did not go to sleep"
  180.     fi
  181. }
  182.  
  183. delay_system ()
  184. {
  185.     if [ "$dry" -eq 1 ]; then
  186.         echo "DRY-RUN: stay awake for $timer_delay"
  187.         sleep 1
  188.         return
  189.     fi
  190.  
  191.     #
  192.     # wait for $timer_delay seconds after system resume from S3
  193.     #
  194.     ECHO "wait for $timer_delay seconds"
  195.     sleep $timer_delay
  196. }
  197.  
  198. ECHO ()
  199. {
  200.     echo "$@" | tee -a "$LOGFILE"
  201. }
  202.  
  203. run_suspend ()
  204. {
  205.     CNT=1
  206.     TOTAL=$1
  207.     ECHO "Suspend Test starting on $(date '+%F %H:%M:%S') ($TOTAL cycles)"
  208.     while [ "$CNT" -le "$TOTAL" ]
  209.     do
  210.         ECHO "Suspend iteration $CNT of $TOTAL"
  211.  
  212.         suspend_system "$START"
  213.         delay_system
  214.  
  215.         (( CNT++ ))
  216.     done
  217.     ECHO "Suspend Test completed"
  218. }
  219.  
  220. enable_trace()
  221. {
  222.     echo 1 > '/sys/power/pm_trace'
  223. }
  224.  
  225. disable_trace()
  226. {
  227.     echo 0 > '/sys/power/pm_trace'
  228. }
  229.  
  230. # Battery
  231. battery_count()
  232. {
  233.     cat /proc/acpi/battery/*/state 2>/dev/null | \
  234.     awk '
  235.         BEGIN            { total = 0 }
  236.         /present:.*yes/        { total += 1 }
  237.         END            { print total }
  238.     '
  239. }
  240. battery_capacity()
  241. {
  242.     cat /proc/acpi/battery/*/state 2>/dev/null | \
  243.     awk '
  244.         BEGIN            { total = 0 }
  245.         /remaining capacity:/    { total += $3 }
  246.         END            { print total }
  247.     '
  248. }
  249.  
  250. #
  251. # MAIN
  252. #
  253. usage() {
  254.     cat - 1>&2 <<EOM
  255. Usage: $P [<options>]
  256. Options:
  257.  --sleep <seconds>         - how long the machine wait before waking
  258.  --delay <seconds>         - default delay between iterations
  259.  
  260.  --enable <test>           - enable a specific test
  261.  --disable <test>          - disable a specific test
  262.  --set <test>.<var>=<val>  - set a test specific variable
  263.      dbus                    - perform a suspend via dbus
  264.      ac                      - perform tests involving removing ac power
  265.      timed                   - perform a variable timing test
  266.      repeat                  - perform a longer repeat test
  267.        .iterations             - the number of iterations in the repeat
  268.      power                   - perform a battery consumption test
  269.        .sleep                  - how long to sleep
  270.  
  271.  --full                    - run a basic set of tests
  272.  --server                  - run those test appropriate for a server
  273. EOM
  274. }
  275.  
  276. # We need TEMP as the `eval set --' would nuke the return value of getopt.
  277. TEMP=`getopt -o '' -l dry-run,auto,,sleep:,delay:,enable:,disable:,set:,full,desktop,server -n "$P" -- "$@"`
  278. if [ $? != 0 ] ; then
  279.     usage
  280.         exit 1
  281. fi
  282.  
  283. # Note the quotes around `$TEMP': they are essential!
  284. eval set -- "$TEMP"
  285.  
  286. # Options helpers.
  287. chk_test ()
  288. {
  289.     if ! declare -p "test_$1" 2>/dev/null 1>&2; then
  290.         echo "$P: $1: test unknown" 1>&2
  291.         exit 1
  292.     fi
  293. }
  294. handle_set ()
  295. {
  296.     stmt=`echo "$1" | sed -e 's/\./_/g'`
  297.  
  298.     test="${stmt%%_*}"
  299.     var="${stmt%%=*}"
  300.  
  301.     chk_test "$test"
  302.     if ! declare -p "args_$var" 2>/dev/null 1>&2; then
  303.         echo "$P: $var: test variable unknown" 1>&2
  304.         exit 1
  305.     fi
  306.     
  307.     RET="args_$stmt"
  308. }
  309. chk_number() {
  310.     eval "val=\"\$$1\""
  311.     let num="0+$val"
  312.     if [ "$val" != "$num" ]; then
  313.         name=`echo "$1" | sed -e 's/args_//' -e 's/_/./'`
  314.         echo "$P: $name: $val: non-numeric value" 1>&2
  315.         exit 1
  316.     fi
  317. }
  318.  
  319. # Options handling.
  320. dry=0
  321. auto=0
  322. timer_sleep=20
  323. timer_delay=10
  324.  
  325. test_dbus=0
  326. test_pmsuspend=0
  327. test_ac=0
  328. test_timed=0
  329. test_repeat=0
  330. args_repeat_iterations=10
  331. test_power=0
  332. args_power_sleep=1200
  333.  
  334. while :
  335. do
  336.         case "$1" in
  337.     --dry-run)        dry=1; shift 1 ;;
  338.     --auto)            auto=1; shift 1 ;;
  339.     --sleep)        timer_sleep="$2"; shift 2 ;;
  340.     --delay)        timer_delay="$2"; shift 2 ;;
  341.     --disable)        chk_test "$2"; declare "test_$1=0"; shift 2 ;;
  342.     --enable)        chk_test "$2"; declare "test_$2=1"; shift 2 ;;
  343.     --set)            handle_set "$2"; declare "$RET"; shift 2 ;;
  344.     --desktop|--full)    test_dbus=1; test_ac=1; test_timed=1;
  345.                 test_power=1; shift 1 ;;
  346.     --server)        test_timed=1; shift 1 ;;
  347.         --)                     shift; break ;;
  348.     *)            echo "$1: ERROR"; exit 1 ;;
  349.         esac
  350. done
  351.  
  352. chk_number "args_repeat_iterations"
  353. chk_number "args_power_sleep"
  354.  
  355. tests=`set | grep ^test_ | grep -c =1`
  356.  
  357. if [ "$#" -gt 1 ]; then
  358.     usage
  359.     exit 1
  360. fi
  361. if [ "$tests" -eq 0 ]; then
  362.     usage
  363.     echo "$P: no tests selected" 1>&2
  364.     exit 1
  365. fi
  366.  
  367. battery_count=`battery_count`
  368.  
  369. report_battery=''
  370.  
  371. suspend_dbus=0
  372.  
  373. # Check we are running as root as we are going to fiddle with the clock
  374. # and use the rtc wakeups.
  375. id=`id -u`
  376. if [ "$id" -ne 0 ]; then
  377.     echo "ERROR: must be run as root to perform this test, use sudo:" 1>&2
  378.     echo "       sudo $0 $@" 1>&2
  379.     exit 1
  380. fi
  381.  
  382. ac_needed=-1
  383. ac_is=-1
  384. ac_becomes=-1
  385. ac_required()
  386. {
  387.     ac_check
  388.  
  389.     ac_needed="$1"
  390.     ac_becomes="$1"
  391. }
  392. ac_transitions()
  393. {
  394.     ac_check
  395.  
  396.     ac_needed="$1"
  397.     ac_becomes="$2"
  398. }
  399. ac_online()
  400. {
  401.     cat /proc/acpi/ac_adapter/*/state 2>/dev/null | \
  402.     awk '
  403.         BEGIN            { online = 0; offline = 0 }
  404.         /on-line/        { online = 1 }
  405.         /off-line/        { offline = 1 }
  406.         END            {
  407.                         if (online) {
  408.                             print "1"
  409.                         } else if (offline) {
  410.                             print "0"
  411.                         } else {
  412.                             print "-1"
  413.                         }
  414.                     }
  415.     '
  416. }
  417. ac_check()
  418. {
  419.     typeset ac_current=`ac_online`
  420.  
  421.     if [ "$ac_becomes" -ne -1 -a "$ac_current" -ne -1 -a \
  422.             "$ac_current" -ne "$ac_becomes" ]; then
  423.         ECHO "*** WARNING: AC power not in expected state" \
  424.             "($ac_becomes) after test"
  425.     fi
  426.     ac_is="$ac_becomes"
  427. }
  428.  
  429. phase=0
  430. phase_first=1
  431. phase_interactive=1
  432. phase()
  433. {
  434.     typeset sleep
  435.  
  436.     let phase="$phase+1"
  437.  
  438.     echo ""
  439.     echo "*** TEST $phase -- $1"
  440.     shift 1
  441.     for line in "$@"
  442.     do
  443.         echo "*** $line"
  444.     done
  445.     if [ "$battery_count" -ne 0 -a "$ac_needed" -ne "$ac_is" ]; then
  446.         case "$ac_needed" in
  447.         0) echo "*** please ensure your AC cord is detached" ;;
  448.         1) echo "*** please ensure your AC cord is attached" ;;
  449.         esac
  450.         ac_is="$ac_needed"
  451.     fi
  452.     
  453.     if [ "$timer_sleep" -gt 60 ]; then
  454.         let sleep="$timer_sleep / 60"
  455.         sleep="$sleep minutes"
  456.     else
  457.         sleep="$timer_sleep seconds"
  458.     fi
  459.     echo "*** machine will suspend for $sleep"
  460.  
  461.     if [ "$auto" -eq 1 ]; then
  462.         :
  463.  
  464.     elif [ "$phase_interactive" -eq 1 ]; then
  465.         echo "*** press return when ready"
  466.         read x
  467.  
  468.     elif [ "$phase_first" -eq 1 ]; then
  469.         echo "*** NOTE: there will be no further user interaction from this point"
  470.         echo "*** press return when ready"
  471.         phase_first=0
  472.         read x
  473.     fi
  474.     echo ""
  475. }
  476.  
  477. [ "$auto" -eq 0 ] && cat - <<EOM
  478. This script will attempt to suspend and resume your computer a number of times.
  479. Should the machine fail to resume, first attempt to manually resume it.  If
  480. that fails power your system off and on which will generate an apport bug
  481. report automatically.
  482.  
  483. Press CTRL-C now to abort testing ...
  484. EOM
  485.  
  486. # Ensure the log directory exists.
  487. mkdir -p "$LOGDIR"
  488.  
  489. phase_interactive=1
  490. if [ "$test_dbus" -eq 1 -a \
  491.         \( "$SUDO_USER" = "" -o "$SUDO_USER" = "root" \) ]; then
  492.     ECHO "*** no primary user (via sudo) dbus tests skipped ..."
  493. elif [ "$test_dbus" -eq 1 ]; then
  494.     ac_required 1
  495.     suspend_dbus=1
  496.     phase "suspend triggered via dbus message"
  497.     suspend_system
  498.     suspend_dbus=0
  499. fi
  500. if [ "$test_pmsuspend" -eq 1 ]; then
  501.     ac_required 1
  502.     phase "suspend triggered via pm-suspend"
  503.     suspend_system
  504. fi
  505. if [ "$test_ac" -eq 1 -a "$battery_count" -eq 0 ]; then
  506.     ECHO "*** no BATTERY detected ac tests skipped ..."
  507. elif [ "$test_ac" -eq 1 ]; then
  508.     ac_required 0
  509.     phase "suspend with AC disconnected"
  510.     suspend_system
  511.  
  512.     ac_required 1
  513.     phase "suspend with AC connected"
  514.     suspend_system
  515.     
  516.     ac_transitions 1 0
  517.     phase "loss of AC while suspended" \
  518.           "please remove the AC cord while the machine is suspended"
  519.     suspend_system
  520.  
  521.     ac_transitions 0 1
  522.     phase "return of AC while suspended" \
  523.           "please insert the AC cord while the machine is suspended"
  524.     suspend_system
  525. fi
  526. if [ "$test_power" -eq 1 -a "$battery_count" -eq 0 ]; then
  527.     ECHO "*** no BATTERY detected power test skipped ..."
  528. elif [ "$test_power" -eq 1 ]; then
  529.     save_timer_sleep="$timer_sleep"
  530.     let timer_sleep="$args_power_sleep"
  531.  
  532.     ac_required 0
  533.     phase "battery drain during suspend" \
  534.           "calculates overall power drain during a long-term suspend"
  535.  
  536.     # get start values
  537.     date_before=`date +%s`
  538.     bat_before=`battery_capacity`
  539.   
  540.     # Suspend
  541.     suspend_system
  542.   
  543.     # get end values
  544.     date_after=`date +%s`
  545.     bat_after=`battery_capacity`
  546.  
  547.     # do the calculations 
  548.     let consumed="$bat_before - $bat_after"
  549.     let elapsed="$date_after - $date_before"
  550.     let usage="($consumed * 60*60) / $elapsed"
  551.  
  552.     # output the results
  553.     ECHO "before: $bat_before mWh"
  554.     ECHO "after: $bat_after mWh"
  555.     ECHO "consumed: $consumed mW"
  556.     ECHO "sleep seconds: $elapsed sec"
  557.     ECHO "overall usage: $usage mW"
  558.      
  559.     report_battery="$usage mW"
  560.  
  561.     if [ $elapsed -lt 1200 ]
  562.     then
  563.         ECHO "WARNING: the suspend was less than 20 minutes"
  564.         ECHO "         to get reliable numbers increase the sleep time"
  565.         report_battery="$report_battery (unreliable)"
  566.     fi
  567.  
  568.     timer_sleep="$save_timer_sleep"
  569. fi
  570.  
  571. phase_interactive=0
  572. if [ "$test_timed" -eq 1 ]; then
  573.     save_timer_delay="$timer_delay"
  574.     timer_delay=60
  575.  
  576.     ac_required 1
  577.     phase "30 iteration variable delay suspend/resume stress test"
  578.     while [ "$timer_delay" -gt 0 ]; do
  579.         echo "delay $timer_delay ..."
  580.         suspend_system
  581.         delay_system
  582.         let timer_delay="$timer_delay - 2"
  583.     done
  584.     timer_delay="$save_timer_delay"
  585. fi
  586. if [ "$test_repeat" -eq 1 ]; then
  587.     ac_required 1
  588.     phase "basic $args_repeat_iterations iteration suspend/resume stress test"
  589.     run_suspend "$args_repeat_iterations"
  590. fi
  591.  
  592. ac_check
  593.  
  594. #
  595. # REPORT: final report stage.
  596. #
  597. report_this()
  598. {    
  599.     if [ "$2" != "" ]; then
  600.         echo "      $1 $2"
  601.     fi
  602. }
  603. if [ "$auto" -eq 0 ]; then
  604.     echo ""
  605.     echo "*** Please report your results on the Ubuntu WIKI:"
  606.     echo "    https://wiki.ubuntu.com/KernelTeam/SuspendResumeTesting"
  607.     echo ""
  608.     report_this "Battery Consumption:" "$report_battery"
  609. fi
  610.  
  611. # All suceessful, clean up.
  612. rm -f "$LOGFILE"
  613.